﻿using Microsoft.AspNetCore.SignalR;
using MultiAgentsClient.ChatDataStructures;
using MultiAgentsShared;
using OpenAI.ObjectModels.RequestModels;

namespace MultiAgentsServer.Scripts.Hubs;

public class SignalRChatHub(IEventBus eventBus) : SignalRBaseHub(eventBus)
{
    #region ApiRequest
    public void SendToolResultApiRequest(Dictionary<string, object> requestParams)
    {
        var sessionId = requestParams.GetData<string>("sessionId");
        var userId = requestParams.GetData<int>("userId");
        var userName = requestParams.GetData<string>("userName");
        var toolCallMessageId = requestParams.GetData<int>("toolCallMessageId");
        var model = requestParams.GetData<string>("model");
        var osSystemMsg = requestParams.GetData<string>("osSystemMsg");
        /// <param name="toolCallResults">Id, toolCallResult</param>
        var toolCallResults = requestParams.GetData<Dictionary<string, string>>("toolCallResults");

        _eventBus.Publish(new SendToolResultCommand(Context.ConnectionId, sessionId, userId, userName, toolCallMessageId, model, osSystemMsg, toolCallResults));
    }

    public void SendUserMsgApiRequest(Dictionary<string, object> requestParams)
    {
        var sessionId = requestParams.GetData<string>("sessionId");
        var userId = requestParams.GetData<int>("userId");
        var userName = requestParams.GetData<string>("userName");
        var roomId = requestParams.GetData<int>("roomId");
        var osSystemMsg = requestParams.GetData<string>("osSystemMsg");
        var message = requestParams.GetData<string>("message");
        var images = requestParams.GetData<Dictionary<string, string>>("images");
        var textFiles = requestParams.GetData<Dictionary<string, string>>("textFiles");
        var model = requestParams.GetData<string>("model");
        var toolSetJson = requestParams.GetData<string>("toolSetJson");
        List<ToolDefinition>? clientEndToolSet = null;
        if (!string.IsNullOrEmpty(toolSetJson))
        {
            clientEndToolSet = ToolsRelatedJsonUtils.DeserializeToolDefs(toolSetJson);
        }

        _eventBus.Publish(new SendUserMsgCommand(Context.ConnectionId, sessionId, userId, userName, roomId, osSystemMsg, message, images, textFiles, model, clientEndToolSet));
    }

    public void SendUserMessageWithoutLLMResponseApiRequest(Dictionary<string, object> requestParams)
    {
        var sessionId = requestParams.GetData<string>("sessionId");
        var userId = requestParams.GetData<int>("userId");
        var userName = requestParams.GetData<string>("userName");
        var roomId = requestParams.GetData<int>("roomId");
        var message = requestParams.GetData<string>("message");

        _eventBus.Publish(new SendUserMessageWithoutLLMResponseCommand(Context.ConnectionId, sessionId, userId, userName, roomId, message));
    }

    public void ResendMessageApiRequest(Dictionary<string, object> requestParams)
    {
        var sessionId = requestParams.GetData<string>("sessionId");
        var userId = requestParams.GetData<int>("userId");
        var messageId = requestParams.GetData<int>("messageId");
        var content = requestParams.GetData<string>("content");
        var model = requestParams.GetData<string>("model");
        var osSystemMsg = requestParams.GetData<string>("osSystemMsg");
        var toolSetJson = requestParams.GetData<string>("toolSetJson");

        List<ToolDefinition>? clientEndToolSet = null;
        if (!string.IsNullOrEmpty(toolSetJson))
        {
            clientEndToolSet = ToolsRelatedJsonUtils.DeserializeToolDefs(toolSetJson);
        }

        _eventBus.Publish(new ResendMessageCommand(Context.ConnectionId, sessionId, userId, messageId, content, model, osSystemMsg, clientEndToolSet));
    }

    public void OverrideMessageApiRequest(Dictionary<string, object> requestParams)
    {
        var sessionId = requestParams.GetData<string>("sessionId");
        var userId = requestParams.GetData<int>("userId");
        var messageId = requestParams.GetData<int>("messageId");
        var content = requestParams.GetData<string>("content");

        _eventBus.Publish(new OverrideMessageCommand(Context.ConnectionId, sessionId, userId, messageId, content));
    }

    public void SendNodeMessageApiRequest(Dictionary<string, object> requestParams)
    {
        var sessionId = requestParams.GetData<string>("sessionId");
        var userId = requestParams.GetData<int>("userId");
        var userName = requestParams.GetData<string>("userName");
        var roomId = requestParams.GetData<int>("roomId");
        var message = requestParams.GetData<string>("message");
        var workflowName = requestParams.GetData<string>("workflowName");

        _eventBus.Publish(new SendNodeMessageCommand(Context.ConnectionId, sessionId, userId, userName, roomId, message, workflowName));
    }

    public void StopUserMsgApiRequest(Dictionary<string, object> requestParams)
    {
        var sessionId = requestParams.GetData<string>("sessionId");
        var userId = requestParams.GetData<int>("userId");

        _eventBus.Publish(new StopUserMsgCommnad(Context.ConnectionId, sessionId, userId));
    }

    public void CreateProjectApiRequest(Dictionary<string, object> requestParams)
    {
        var sessionId = requestParams.GetData<string>("sessionId");
        var userId = requestParams.GetData<int>("userId");
        var projectName = requestParams.GetData<string>("projectName");
        var projectSettings = requestParams.GetData<string>("projectSettings");

        _eventBus.Publish(new CreateProjectCommand(Context.ConnectionId, sessionId, userId, projectName, projectSettings));
    }

    public void DeleteProjectApiRequest(Dictionary<string, object> requestParams)
    {
        var sessionId = requestParams.GetData<string>("sessionId");
        var userId = requestParams.GetData<int>("userId");
        var projectId = requestParams.GetData<int>("projectId");

        _eventBus.Publish(new DeleteProjectCommand(Context.ConnectionId, sessionId, userId, projectId));
    }

    public void CreateChatRoomApiRequest(Dictionary<string, object> requestParams)
    {
        var sessionId = requestParams.GetData<string>("sessionId");
        var userId = requestParams.GetData<int>("userId");
        var projectId = requestParams.GetData<int>("projectId");
        var chatRoomName = requestParams.GetData<string>("chatRoomName");

        _eventBus.Publish(new CreateChatRoomCommand(Context.ConnectionId, sessionId, userId, projectId, chatRoomName));
    }

    public void SwitchChatRoomApiRequest(Dictionary<string, object> requestParams)
    {
        var sessionId = requestParams.GetData<string>("sessionId");
        var userId = requestParams.GetData<int>("userId");
        var chatRoomId = requestParams.GetData<int>("chatRoomId");

        _eventBus.Publish(new SwitchChatRoomCommand(Context.ConnectionId, sessionId, userId, chatRoomId));
    }

    public void GetFileContentApiRequest(Dictionary<string, object> requestParams)
    {
        var sessionId = requestParams.GetData<string>("sessionId");
        var userId = requestParams.GetData<int>("userId");
        var imageId = requestParams.GetData<int>("imageId");

        _eventBus.Publish(new GetFileContentCommand(Context.ConnectionId, sessionId, userId, imageId));
    }

    public void SwitchChatRoomBranchApiRequest(Dictionary<string, object> requestParams)
    {
        var sessionId = requestParams.GetData<string>("sessionId");
        var userId = requestParams.GetData<int>("userId");
        var chatRoomId = requestParams.GetData<int>("chatRoomId");
        var messageId = requestParams.GetData<int>("messageId");

        _eventBus.Publish(new SwitchChatRoomBranchCommand(Context.ConnectionId, sessionId, userId, chatRoomId, messageId));
    }
    #endregion

    #region ApiResponse
    public static async Task SendUserMessageApiUserResponse(IHubContext<SignalRChatHub> hubContext, string connectionId, int roomId, ChatMessageData chatMessageData, string? mentionedAgent)
    {
        string messageJson = chatMessageData.ConvertToJson();
        await hubContext.Clients.Client(connectionId).SendAsync("SendUserMsgApiResponse", roomId, messageJson, mentionedAgent);
    }

    public static async Task OverrideMessageApiResponse(IHubContext<SignalRChatHub> hubContext, string connectionId, int messageId, string message)
    {
        await hubContext.Clients.Client(connectionId).SendAsync("OverrideMessageApiResponse", messageId, message);
    }

    public static async Task SendUserMessageApiAgentResponse(IHubContext<SignalRChatHub> hubContext, string connectionId, int userId, int roomId, int msgId, int sliceIndex, List<int>? historyMessagesIdList, string agentAuthor, string? msgSlice, string? toolCallsJson = null)
    {
        var messageData = new Dictionary<string, object?>
        {
            { "userId", userId },
            { "roomId", roomId },
            { "msgId", msgId },
            { "sliceIndex", sliceIndex },
            { "author", agentAuthor },
            { "historyMessagesIdList", historyMessagesIdList },
            { "msgSlice", msgSlice },
            { "toolCallsJson", toolCallsJson },
            { "time", DateTime.Now }
        };

        await hubContext.Clients.Client(connectionId).SendAsync("ReceiveStream", messageData);

        if (msgSlice == null && toolCallsJson == null)
        {
            Debug.LogLine("\nResponse finished.");
        }
    }

    public static async Task ReplyAssistantOptionsResponse(IHubContext<SignalRChatHub> hubContext, string connectionId, int chatRoomId, List<string> options)
    {
        await hubContext.Clients.Client(connectionId).SendAsync("ReplyAssistantOptionsResponse", chatRoomId, options);
    }

    public static async Task SendToolResultApiResponse(IHubContext<SignalRChatHub> hubContext, string connectionId, int msgId, int userId, int roomId, string toolCallId, string toolCallResult, List<int>? historyMessagesIdList)
    {
        //this is to acknowledge sendUserMsgRequest
        await hubContext.Clients.Client(connectionId).SendAsync("SendToolResultApiResponse", msgId, userId, roomId, toolCallId, toolCallResult, historyMessagesIdList, DateTime.Now);
    }

    public static async Task CreateProjectApiResponse(IHubContext<SignalRChatHub> hubContext, string connectionId, int projectId, string projectName, string prjSettings)
    {
        await hubContext.Clients.Client(connectionId).SendAsync("CreateProjectApiResponse", projectId, projectName, prjSettings);
    }

    public static async Task DeleteProjectApiResponse(IHubContext<SignalRChatHub> hubContext, string connectionId, int projectId)
    {
        await hubContext.Clients.Client(connectionId).SendAsync("DeleteProjectApiResponse", projectId);
    }

    public static async Task CreateChatRoomApiResponse(IHubContext<SignalRChatHub> hubContext, string connectionId, int chatRoomId, int projectId, string chatRoomName)
    {
        await hubContext.Clients.Client(connectionId).SendAsync("CreateChatRoomApiResponse", chatRoomId, projectId, chatRoomName);
    }

    public static async Task SwitchChatRoomApiResponse(IHubContext<SignalRChatHub> hubContext, string connectionId, int chatRoomId, int projectId, List<ChatMessageData> messages, int lastMessageId)
    {
        ChatRoom chatRoom = new();
        List<string> messagesJson = messages.Select(message => message.ConvertToJson()).ToList();
        await hubContext.Clients.Client(connectionId).SendAsync("SwitchChatRoomApiResponse", chatRoomId, projectId, messagesJson, lastMessageId);
    }

    public static async Task SwitchChatRoomBranchApiResponse(IHubContext<SignalRChatHub> hubContext, string connectionId, int chatRoomId, int messageId)
    {
        await hubContext.Clients.Client(connectionId).SendAsync("SwitchChatRoomBranchApiResponse", chatRoomId, messageId);
    }

    public static async Task GetFileContentApiResponse(IHubContext<SignalRChatHub> hubContext, string connectionId, int fileId, string fileType, string fileContent)
    {
        await hubContext.Clients.Client(connectionId).SendAsync("GetFileContentApiResponse", fileId, fileType, fileContent);
    }
    #endregion
}
